package cn.iocoder.yudao.module.brokerage.merchant.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.business.order.pojo.vo.OrderSnapshotVO;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.util.TransactionUtils;
import cn.iocoder.yudao.module.api.brokerage.record.enums.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.api.infrastructure.config.ConfigApiV2;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.BrokerageConfigRespDTO;
import cn.iocoder.yudao.module.api.shop.info.dto.ShopInfoDTO;
import cn.iocoder.yudao.module.api.trade.order.TradeOrderApi;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderItemRespDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.api.trade.scan.dto.ScanOrderDTO;
import cn.iocoder.yudao.module.brokerage.merchant.dao.BrokerageMerchantMapper;
import cn.iocoder.yudao.module.brokerage.merchant.dao.BrokerageMerchantRecordMapper;
import cn.iocoder.yudao.module.brokerage.merchant.pojo.po.AgencyBrokerageRecordDO;
import cn.iocoder.yudao.module.brokerage.merchant.pojo.po.AgencyMerchantDO;
import cn.iocoder.yudao.module.brokerage.record.mq.BrokerageRecordProducer;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static cn.iocoder.yudao.module.api.infrastructure.ConfigConstants.CONFIG_BROKERAGE;

/**
 * 佣金记录 Service 实现类
 *
 * @author owen
 */
@Slf4j
@Service
@Validated
public class BrokerageMerchantRecordServiceImpl implements BrokerageMerchantRecordService {

    @Resource
    private BrokerageMerchantRecordMapper brokerageMerchantRecordMapper;
    @Resource
    private BrokerageMerchantMapper brokerageMerchantMapper;

    @Resource
    private BrokerageRecordProducer brokerageRecordProducer;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private ConfigApiV2 configApiV2;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderApi tradeOrderApi;

    @Override
    public void addBrokerageWhenOrderPaid(TradeOrderRespDTO order) {
        AgencyMerchantDO merchantDO = brokerageMerchantMapper.findOrCreateByShopId(order.getShopId());
        if (merchantDO.getAgencyUserId() == null || merchantDO.getAgencyUserId() <= 0) {
            log.warn("[addBrokerageWhenOrderPaid/TradeOrder][tradeNo({})][shopId({}) 分佣失败：店铺未绑定招商人员]", order.getNo(), order.getShopId());
            return;
        }
        long brokerageUserId = merchantDO.getAgencyUserId();
        BrokerageConfigRespDTO configRespDTO = configApiV2.getConfig(CONFIG_BROKERAGE, BrokerageConfigRespDTO.class);
        String note = null;
        boolean valid = true;
        if (!configRespDTO.isEnabled()) {
            log.error("[addBrokerageWhenOrderPaid/TradeOrder][推广分佣功能未开启，userId({}) tradeNo({})", brokerageUserId, order.getNo());
            note = "商家流水分佣无效：推广分佣功能未开启";
            valid = false;
        }
        List<TradeOrderItemRespDTO> orderItems = tradeOrderApi.getOrderItemsByOrderId(order.getId());
        if (CollUtil.isEmpty(orderItems)) {
            log.error("[addBrokerageWhenOrderPaid/TradeOrder][订单项不存在，userId({}) tradeNo({})", brokerageUserId, order.getNo());
            note = "消费分佣无效：订单项不存在";
            valid = false;
        }
        try {
            List<AgencyBrokerageRecordDO> records = new ArrayList<>(orderItems.size());
            // 每一个订单项都去生成分佣记录以便于退款时扣除已分配的佣金
            for (TradeOrderItemRespDTO orderItem : orderItems) {
                AgencyBrokerageRecordDO record = new AgencyBrokerageRecordDO();
                record.setUserId(brokerageUserId);
                record.setTradeNo(order.getNo());
                record.setOrderItemId(orderItem.getId());
                record.setBonusPercent(configRespDTO.getShopIncomePercent());
                int basePrice = valid ? orderItem.getPayPrice() : 0;
                record.setBasePrice(basePrice);
                OrderSnapshotVO snapshotVO = new OrderSnapshotVO();
                snapshotVO.setName(orderItem.getSpuName());
                snapshotVO.setPicUrl(orderItem.getPicUrl());
                snapshotVO.setCount(orderItem.getCount());
                snapshotVO.setOriginPrice(orderItem.getPrice());
                snapshotVO.setPayPrice(orderItem.getPayPrice());
                record.setOrderSnapshot(JSONUtil.toJsonStr(snapshotVO));
                double bonusPercent = record.getBonusPercent();
                int bonusMoney = MoneyUtils.calculateRatePriceFloor(basePrice, bonusPercent);
                record.setBonusPercent(bonusPercent);
                record.setBonusMoney(bonusMoney);
                record.setSourceUserId(orderItem.getUserId());
                record.setSourceShopId(orderItem.getShopId());
                if (bonusMoney == 0) {
                    record.setStatus(BrokerageRecordStatusEnum.CLOSED.getValue());
                    record.setUnfreezeTime(LocalDateTime.now());
                } else {
                    record.setStatus(BrokerageRecordStatusEnum.FREEZING.getValue());
                    record.setUnfreezeTime(LocalDateTime.now().plusDays(15));
                }
                if (StrUtil.isBlank(note)) {
                    note = "商家售出产品 ¥%s，获得推广收益 ¥%s".formatted(MoneyUtils.fenToYuanStr(order.getTotalPrice()), MoneyUtils.fenToYuanStr(bonusMoney));
                }
                record.setNote(note);
                record.setCancelTime(null);
                records.add(record);
            }
            brokerageMerchantRecordMapper.insertBatch(records);
        } catch (Exception e) {
            log.error("[addBrokerageWhenOrderPaid/TradeOrder] 商家流水分佣出错", e);
        }
    }

    @Override
    public void addBrokerageWhenOrderPaid(ScanOrderDTO order) {
        // 商家收款码收款时，上级招商人员分佣
        AgencyMerchantDO merchantDO = brokerageMerchantMapper.findOrCreateByShopId(order.getShopId());
        if (merchantDO.getAgencyUserId() == null || merchantDO.getAgencyUserId() <= 0) {
            log.warn("[addBrokerageWhenOrderPaid/ScanOrder][tradeNo({})][shopId({}) 分佣失败：店铺未绑定招商人员]", order.getTradeNo(), order.getShopId());
            return;
        }
        long brokerageUserId = merchantDO.getAgencyUserId();
        log.info("[addBrokerageWhenOrderPaid/ScanOrder] 商家({})收款({})，给相关招商人员({})分佣", order.getShopId(), order.getTradeNo(), brokerageUserId);
        addBrokerage(brokerageUserId, order);
    }

    private void addBrokerage(Long brokerageUserId, ScanOrderDTO order) {
        BrokerageConfigRespDTO configRespDTO = configApiV2.getConfig(CONFIG_BROKERAGE, BrokerageConfigRespDTO.class);
        String note = null;
        boolean valid = true;
        ShopInfoDTO shop = order.getShop();
        if (!configRespDTO.isEnabled()) {
            log.error("[addBrokerage/ScanOrder][推广分佣功能未开启，userId({}) tradeNo({})", brokerageUserId, order.getTradeNo());
            note = "商家流水分佣无效：推广分佣功能未开启";
            valid = false;
        }
        try {
            AgencyBrokerageRecordDO record = new AgencyBrokerageRecordDO();
            record.setUserId(brokerageUserId);
            record.setTradeNo(order.getTradeNo());
            record.setOrderItemId(0L);
            record.setBonusPercent(configRespDTO.getShopIncomePercent());
            int basePrice = valid ? order.getPrice() : 0;
            record.setBasePrice(basePrice);
            OrderSnapshotVO snapshotVO = new OrderSnapshotVO();
            snapshotVO.setName("商家收款码到账");
            snapshotVO.setPicUrl("");
            snapshotVO.setCount(1);
            snapshotVO.setOriginPrice(order.getOriginPrice());
            snapshotVO.setPayPrice(order.getPrice());
            record.setOrderSnapshot(JSONUtil.toJsonStr(snapshotVO));
            double bonusPercent = record.getBonusPercent();
            int bonusMoney = MoneyUtils.calculateRatePriceFloor(basePrice, bonusPercent);
            record.setBonusPercent(bonusPercent);
            record.setBonusMoney(bonusMoney);
            record.setSourceUserId(order.getUserId());
            record.setSourceShopId(order.getShopId());
            if (bonusMoney == 0) {
                record.setStatus(BrokerageRecordStatusEnum.CLOSED.getValue());
                record.setUnfreezeTime(LocalDateTime.now());
            } else {
                record.setStatus(BrokerageRecordStatusEnum.FREEZING.getValue());
                record.setUnfreezeTime(LocalDateTime.now().plusDays(15));
            }
            if (StrUtil.isBlank(note)) {
                note = "商家%s收款【%s元】，获得推广收益【%s元】".formatted(shop == null ? "" : "【" + shop.getName() + "】", MoneyUtils.fenToYuanStr(order.getPrice()), MoneyUtils.fenToYuanStr(bonusMoney));
            }
            record.setNote(note);
            record.setCancelTime(null);
            brokerageMerchantRecordMapper.insert(record);
        } catch (Exception e) {
            log.error("[addBrokerage/ScanOrder] 商家流水分佣出错", e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelBrokerage(TradeOrderRespDTO order, TradeOrderItemRespDTO orderItem) {
        AgencyMerchantDO merchantDO = brokerageMerchantMapper.findOrCreateByShopId(order.getShopId());
        if (merchantDO.getAgencyUserId() == null || merchantDO.getAgencyUserId() <= 0) {
            log.warn("[cancelBrokerage/TradeOrder][tradeNo({})][shopId({}) 分佣失败：店铺未绑定招商人员]", order.getNo(), order.getShopId());
            return;
        }
        AgencyBrokerageRecordDO record = brokerageMerchantRecordMapper.selectByUserIdAndOrderItemId(merchantDO.getAgencyUserId(), order.getNo(), orderItem.getId());
        if (record == null) {
            log.error("[cancelBrokerage/TradeOrder][userId({})][tradeNo({})[orderItemId({}) 更新佣金记录为已取消失败：记录不存在]", merchantDO.getAgencyUserId(), order.getNo(), orderItem.getId());
            return;
        }
        // 更新佣金记录为已取消
        AgencyBrokerageRecordDO updateObj = new AgencyBrokerageRecordDO();
        updateObj.setStatus(BrokerageRecordStatusEnum.CANCEL.getValue());
        updateObj.setCancelTime(LocalDateTime.now());
        int updateRows = brokerageMerchantRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
        if (updateRows == 0) {
            log.error("[cancelBrokerage/TradeOrder][record({}) 更新佣金记录为已取消失败]", record.getId());
            return;
        }
        log.info("[cancelBrokerage][userId({})][tradeNo({}) 更新佣金记录为已取消成功]", merchantDO.getAgencyUserId(), record.getTradeNo());
        if (!BrokerageRecordStatusEnum.UNFREEZE.getValue().equals(record.getStatus())) {
            return;
        }
        brokerageRecordProducer.sendCommissionCancelMessage(record.getUserId(), record.getTradeNo(), record.getBasePrice(), record.getBonusMoney());
    }

    @Override
    public int unfreezeRecord() {
        // 1. 查询待解冻的佣金记录
        List<AgencyBrokerageRecordDO> records = brokerageMerchantRecordMapper.selectListByStatusAndLessThanUnfreezeTime(
                BrokerageRecordStatusEnum.FREEZING.getValue(), LocalDateTime.now());
        if (CollUtil.isEmpty(records)) {
            log.debug("[unfreezeUserRecord][无待解冻的佣金记录]");
            return 0;
        }
        // 2. 遍历执行
        int count = 0;
        for (AgencyBrokerageRecordDO record : records) {
            try {
                if (SpringUtil.getBean(getClass()).unfreezeRecord(record)) {
                    count++;
                }
            } catch (Exception e) {
                log.error("[unfreezeUserRecord][record({}) 更新为已结算失败]", record.getId(), e);
            }
        }
        log.info("[unfreezeUserRecord][count({})]", count);
        return count;
    }

    @Override
    public boolean unfreezeRecord(AgencyBrokerageRecordDO record) {
        Boolean result = TransactionUtils.transactional(() -> {
            // 更新记录状态
            AgencyBrokerageRecordDO updateObj = new AgencyBrokerageRecordDO();
            if (record.getBonusMoney() <= 0) {
                updateObj.setStatus(BrokerageRecordStatusEnum.CLOSED.getValue());
                updateObj.setUnfreezeTime(LocalDateTime.now());
                int updateRows = brokerageMerchantRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
                if (updateRows == 0) {
                    log.error("[unfreezeUserRecord][record({}) 更新为已失效失败]", record.getId());
                    return false;
                }
                return true;
            }
            updateObj.setStatus(BrokerageRecordStatusEnum.UNFREEZE.getValue());
            updateObj.setUnfreezeTime(LocalDateTime.now());
            int updateRows = brokerageMerchantRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
            log.info("[unfreezeUserRecord][record({}) 更新为已结算结果：{}]", record.getId(), updateRows > 0);
            if (updateRows == 0) {
                return false;
            }
            brokerageRecordProducer.sendCommissionUnfreezeMessage(record.getUserId(), record.getTradeNo(), record.getBasePrice(), record.getBonusMoney());
            return true;
        });
        return Boolean.TRUE.equals(result);
    }

}
